home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / reve / x11.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-27  |  29.7 KB  |  1,018 lines

  1. /*LINTLIBRARY*/
  2.  
  3. /*  @(#)x11.c 1.26 91/11/13
  4.  *
  5.  *  X11 dependent graphics routines used by reve.
  6.  *
  7.  *  Copyright (c) 1990, 1991 - Rich Burridge & Yves Gallot.
  8.  *  All rights reserved.
  9.  *
  10.  *  Permission is granted to copy this source, for redistribution
  11.  *  in source form only, provided the news headers in "substantially
  12.  *  unaltered format" are retained, the introductory messages are not
  13.  *  removed, and no monies are exchanged.
  14.  *
  15.  *  Permission is also granted to copy this source, without the
  16.  *  news headers, for the purposes of making an executable copy by
  17.  *  means of compilation, provided that such copy will not be used
  18.  *  for the purposes of competition in any othello tournaments, without
  19.  *  prior permission from the authors.
  20.  *
  21.  *  No responsibility is taken for any errors or inaccuracies inherent
  22.  *  either to the comments or the code of this program, but if reported
  23.  *  (see README file), then an attempt will be made to fix them.
  24.  */
  25.  
  26. #include "reve.h"
  27. #include "color.h"
  28. #include "extern.h"
  29. #include "images.h"
  30. #include <ctype.h>
  31. #include <limits.h>
  32. #include <signal.h>
  33. #include <sys/param.h>
  34. //#include <sys/time.h>
  35.  
  36. #ifdef HASPOLL
  37. #include <poll.h>
  38. #endif /*HASPOLL*/
  39.  
  40. #include <X11/Xlib.h>
  41. #include <X11/Xutil.h>
  42. #include <X11/Xatom.h>
  43. #include <X11/Xos.h>
  44. #include <X11/cursorfont.h>
  45. #include <X11/keysym.h>
  46. #include <X11/Xresource.h>
  47.  
  48. #define  SOCK_INPUT   0      /* Types of input selected on. */
  49. #define  COMP_INPUT   1
  50. #define  DPY_INPUT    2
  51.  
  52. #define  BOARDFONT   "lucidasanstypewriter-10"
  53. #define  BOLDFONT    "lucidasanstypewriter-bold-12"
  54. #define  DEFFONT     "fixed"
  55. #define  HELPFONT    "lucidasanstypewriter-10"
  56. #define  NORMALFONT  "lucidasanstypewriter-12"
  57.  
  58. #define  FRAME_MASK  (ButtonPressMask | ButtonReleaseMask | ExposureMask    | \
  59.                       EnterWindowMask | KeyPressMask      | LeaveWindowMask | \
  60.                       PointerMotionMask | StructureNotifyMask)
  61.  
  62. #define  BORDER_SIZE        6
  63. #define  LABEL_SIZE         27
  64. #define  REVE_BORDER_WIDTH  2
  65.  
  66. enum gr_type gtype = GX11 ;        /* Graphics type. */
  67.  
  68. static void get_event      P(()) ;
  69. static void load_colors    P(()) ;
  70.  
  71. static int process_expose  P((XExposeEvent *)) ;
  72.  
  73. static Window get_wtype    P((enum win_type)) ;
  74.  
  75. Pixmap load_image          P((unsigned char *)) ;
  76. Window make_subwindow      P((int, int, int, int,
  77.                               char *, char *, int, char **)) ;
  78. XFontStruct *get_font      P((char *, char *)) ;
  79.  
  80. Atom protocol_atom, kill_atom ;
  81. Cursor cursor[MAXCURSORS] ;
  82. Display *dpy ;
  83. GC gc ;                         /* Graphics context for text and lines. */
  84. GC igc ;                        /* Graphics content for 1bit images. */
  85. GC ropgc ;                      /* Graphics context for rops. */
  86. GC stencilgc ;                  /* Graphics context for stencils. */
  87. Pixmap images[MAXIMAGES], no_pixmap, reve_icon ;
  88.  
  89. Visual *visual ;                /* Default visual for this display. */
  90. Window cframe ;                 /* Control panel frames. */
  91. Window gframe ;                 /* Game board frames. */
  92. Window hframe ;                 /* Help window frames. */
  93. Window pframe ;                 /* Property window frames. */
  94. Window root ;
  95.  
  96. XClassHint class_hint = { "reve", "Reve" } ;
  97. XColor BGcolor, FGcolor ;
  98. XEvent event ;
  99. XFontStruct *font[MAXFONTS] ;
  100. XrmDatabase reve_DB ;           /* Combined resources database. */
  101. XSizeHints size ;
  102. XWMHints wm_hints ;
  103. XGCValues gc_val ;              /* Used to setup graphics context values. */
  104. int gc_flags ;                  /* Used to set up graphics context flags. */
  105. int screen ;                    /* Default graphics display screen. */
  106. int xfd ;                       /* Server connection file descriptors. */
  107. unsigned long backgnd ;         /* Default background color. */
  108. unsigned long foregnd ;         /* Default foreground color. */
  109. unsigned long gc_mask ;         /* Mask for setting graphic context values. */
  110. unsigned long palette[REVE_COLORSIZE] ;     /* Xlib color palette. */
  111.  
  112. #ifdef NOSELECT
  113. #ifdef HASPOLL
  114. struct pollfd pfd[3] ;
  115. unsigned long npfd ;         /* Number of file descriptors to monitor. */
  116. #endif /*HASPOLL*/
  117. #else /*NOSELECT*/
  118. #ifdef NO_43SELECT
  119. int fullmask ;               /* Full mask of file descriptors to check on. */
  120. int readmask ;               /* Readmask used in select call. */
  121. #else
  122. fd_set fullmask ;            /* Full mask of file descriptors to check on. */
  123. fd_set readmask ;            /* Readmask used in select call. */
  124. #endif /*NO_43SELECT*/
  125. #endif /*NOSELECT*/
  126.  
  127. int opvals[3] ;              /* Pixrect rasterop values. */
  128. unsigned int scr_depth ;
  129.  
  130.  
  131. /*ARGSUSED*/
  132. void
  133. batch(state)     /* Turn graphics batching on or off. */
  134. enum bltype state ;
  135. {
  136.   XFlush(dpy) ;
  137. }
  138.  
  139.  
  140. void
  141. beep()
  142. {
  143.   XBell(dpy, 56) ;
  144.   XFlush(dpy) ;
  145. }
  146.  
  147.  
  148. void
  149. close_reve()
  150. {
  151.   XEvent event ;
  152.  
  153.   event.xclient.type         = ClientMessage ;
  154.   event.xclient.display      = dpy ;
  155.   event.xclient.window       = gframe ;
  156.   event.xclient.message_type = XInternAtom(dpy, "WM_CHANGE_STATE", False) ;
  157.   event.xclient.format       = 32 ;
  158.   event.xclient.data.l[0]    = IconicState ;
  159.   XSendEvent(dpy, DefaultRootWindow(dpy), False,
  160.               SubstructureRedirectMask | SubstructureNotifyMask, &event) ;
  161.   XFlush(dpy) ;
  162. }
  163.  
  164.  
  165. void
  166. color_area(wtype, x, y, width, height, color)
  167. enum win_type wtype ;
  168. int x, y, width, height, color ;
  169. {
  170.   Window window = get_wtype(wtype) ;
  171.  
  172.   if (iscolor) gc_val.foreground = palette[color] ;
  173.   else
  174.     { 
  175.       if (color == C_WHITE) gc_val.foreground = backgnd ;
  176.       else                  gc_val.foreground = foregnd ;
  177.     }
  178.   gc_val.function = GXcopy ;
  179.   XChangeGC(dpy, gc, GCForeground | GCFunction, &gc_val) ;
  180.   XFillRectangle(dpy, window, gc, x, y,
  181.                  (unsigned int) width, (unsigned int) height) ;
  182. }
  183.  
  184.  
  185. void
  186. connect_io()     /* Connect to X server, computer process and remote human. */
  187. {
  188. #ifdef NOSELECT
  189. #ifdef HASPOLL
  190.   npfd = 0L ;
  191.   pfd[0].fd = pfd[1].fd = pfd[2].fd = -1 ;
  192.   pfd[0].events = pfd[1].events = pfd[2].events = POLLIN ;
  193.                          pfd[0].fd = xfd,           npfd++ ;   /* X server. */
  194.   if (pipe_io[1][0] > 0) pfd[1].fd = pipe_io[1][0], npfd++ ;   /* Computer. */
  195.   if (socketfd      > 0) pfd[2].fd = socketfd,      npfd++ ;   /* Human. */
  196. #endif /*HASPOLL*/
  197. #else
  198. #ifdef NO_43SELECT
  199.   fullmask = 0 ;
  200.                          fullmask |= (1 << xfd) ;              /* X server. */
  201.   if (pipe_io[1][0] > 0) fullmask |= (1 << pipe_io[1][0]) ;    /* Computer. */
  202.   if (socketfd      > 0) fullmask |= (1 << socketfd) ;         /* Human. */
  203. #else
  204.   FD_ZERO(&fullmask) ;
  205.                          FD_SET(xfd,           &fullmask) ;    /* X server. */
  206.   if (pipe_io[1][0] > 0) FD_SET(pipe_io[1][0], &fullmask) ;    /* Computer. */
  207.   if (socketfd      > 0) FD_SET(socketfd,      &fullmask) ;    /* Human. */
  208. #endif /*NO_43SELECT*/
  209. #endif /*NOSELECT*/
  210. }
  211.  
  212.  
  213. void
  214. destroy_reve()          /* Terminate reve. */
  215. {
  216.   KILL(pid, SIGKILL) ;
  217.   XDestroyWindow(dpy, gframe) ;
  218.   exit(0) ;
  219. }
  220.  
  221.  
  222. void
  223. draw_image(wtype, x, y, width, height, image)
  224. enum win_type wtype ;
  225. int x, y, width, height ;
  226. enum image_type image ;
  227. {
  228.   Window window = get_wtype(wtype) ;
  229.  
  230.   gc_mask            = GCStipple | GCTileStipXOrigin | GCTileStipYOrigin ;
  231.   gc_val.stipple     = images[(int) image] ;
  232.   gc_val.ts_x_origin = x ;
  233.   gc_val.ts_y_origin = y ;
  234.   XChangeGC(dpy, ropgc, gc_mask, &gc_val) ;
  235.   XFillRectangle(dpy, window, ropgc, x, y, width, height) ;
  236. }
  237.  
  238.  
  239. void
  240. draw_line(wtype, x1, y1, x2, y2, op, color)
  241. enum win_type wtype ;
  242. int x1, y1, x2, y2, color ;
  243. enum optype op ;
  244. {
  245.   Window window = get_wtype(wtype) ;
  246.  
  247.   if (iscolor) gc_val.foreground = palette[color] ;
  248.   else
  249.     {
  250.       if (color == C_WHITE) gc_val.foreground = backgnd ;
  251.       else                  gc_val.foreground = foregnd ;
  252.     }
  253.   gc_val.function = opvals[(int) op] ;
  254.   XChangeGC(dpy, gc, GCForeground | GCFunction, &gc_val) ;
  255.   XDrawLine(dpy, window, gc, x1, y1, x2, y2) ;
  256. }
  257.  
  258.  
  259. void
  260. draw_stencil(wtype, x, y, width, height, op, color, stencil, image)
  261. enum win_type wtype ;
  262. int x, y, width, height, color ;
  263. enum optype op ;
  264. enum image_type stencil, image ;
  265. {
  266.   Window window = get_wtype(wtype) ;
  267.  
  268.   if (iscolor) gc_val.foreground = palette[color] ;
  269.   else         gc_val.foreground = foregnd ;
  270.   gc_val.function      = opvals[(int) op] ;
  271.   gc_val.clip_x_origin = x ;
  272.   gc_val.clip_y_origin = y ;
  273.   gc_val.clip_mask     = images[(int) stencil] ;
  274.   gc_val.stipple       = images[(int) image] ;
  275.   gc_val.ts_x_origin   = x ;
  276.   gc_val.ts_y_origin   = y ;
  277.   gc_mask = GCForeground | GCFunction | GCClipMask |
  278.             GCClipXOrigin | GCClipYOrigin |
  279.             GCStipple | GCTileStipXOrigin | GCTileStipYOrigin ;
  280.   XChangeGC(dpy, stencilgc, gc_mask, &gc_val) ;
  281.   XFillRectangle(dpy, window, stencilgc, x, y, width, height) ;
  282. }
  283.  
  284.  
  285. void
  286. draw_text(wtype, x, y, ftype, color, str)
  287. enum win_type wtype ;
  288. enum font_type ftype ;
  289. int x, y, color ;
  290. char *str ;
  291. {
  292.   Window window = get_wtype(wtype) ;
  293.  
  294.   if (iscolor) gc_val.foreground = palette[color] ;
  295.   else
  296.     { 
  297.       if (color == C_WHITE) gc_val.foreground = backgnd ;
  298.       else                  gc_val.foreground = foregnd ;
  299.     }
  300.   gc_val.font = font[(int) ftype]->fid ;
  301.   gc_val.function = GXcopy ;
  302.   XChangeGC(dpy, gc, GCFont | GCForeground | GCFunction, &gc_val) ;
  303.   XDrawString(dpy, window, gc, x, y, str, strlen(str)) ;
  304. }
  305.  
  306.  
  307. static void
  308. get_event()         /* Get the next canvas event. */
  309. {
  310.   XSync(dpy, 0) ;
  311.   if (!XCheckMaskEvent(dpy, ExposureMask, &event))
  312.     XNextEvent(dpy, &event) ;
  313. }
  314.  
  315.  
  316. XFontStruct *
  317. get_font(name, defname)
  318. char *name, *defname ;
  319. {
  320.   XFontStruct *f ;
  321.  
  322.   if (name == NULL || !(f = XLoadQueryFont(dpy, name)))
  323.     if (!(f = XLoadQueryFont(dpy, defname)))
  324.       if (!(f = XLoadQueryFont(dpy, DEFFONT)))
  325.         {
  326.           FPRINTF(stderr, "%s: couldn't get the default font.", progname) ;
  327.           exit(1) ;
  328.         }
  329.   return(f) ;
  330. }
  331.  
  332.  
  333. char *
  334. get_resource(rtype)      /* Get Reve resource from merged databases. */
  335. enum res_type rtype ;
  336. {
  337.   char cstr[MAXLINE], nstr[MAXLINE], str[MAXLINE] ;
  338.   char *str_type[20] ;
  339.   XrmValue value ;
  340.  
  341.   STRCPY(str, resources[(int) rtype]) ;
  342.   SPRINTF(nstr,  "reve.%s", str) ;
  343.   if (islower(str[0])) str[0] = toupper(str[0]) ;
  344.   SPRINTF(cstr, "Reve.%s", str) ;
  345.   if (XrmGetResource(reve_DB, nstr, cstr, str_type, &value) == NULL)
  346.     return((char *) NULL) ;
  347.   else return(value.addr) ;
  348. }
  349.  
  350.  
  351. int
  352. get_strwidth(ftype, str)    /* Get width in pixels of string value. */
  353. enum font_type ftype ;
  354. char *str ;
  355. {
  356.   return(XTextWidth(font[(int) ftype], str, strlen(str))) ;
  357. }
  358.  
  359.  
  360. static Window
  361. get_wtype(wtype)
  362. enum win_type wtype ;
  363. {
  364.        if (wtype == W_BOARD) return(gframe) ;
  365.   else if (wtype == W_PANEL) return(cframe) ;
  366.   else if (wtype == W_PROPS) return(pframe) ;
  367.   else if (wtype == W_HELP)  return(hframe) ;
  368. }
  369.  
  370.  
  371. void
  372. init_fonts()             /* Open the normal and bold fonts. */
  373. {
  374.   int i ;
  375.  
  376.   font[(int) BFONT] = get_font(fontnames[(int) BFONT], BOLDFONT) ;
  377.   font[(int) GFONT] = get_font(fontnames[(int) GFONT], BOARDFONT) ;
  378.   font[(int) HFONT] = get_font(fontnames[(int) HFONT], HELPFONT) ;
  379.   font[(int) NFONT] = get_font(fontnames[(int) NFONT], NORMALFONT) ;
  380.  
  381.   for (i = 0; i < MAXFONTS; i++)
  382.     font_heights[i] = font[i]->max_bounds.ascent +
  383.                       font[i]->max_bounds.descent ;
  384. }
  385.  
  386.  
  387. /*ARGSUSED*/
  388. void
  389. init_graphics(argc, argv)
  390. int *argc ;
  391. char *argv[] ;
  392. {
  393.   if ((dpy = XOpenDisplay(display)) == NULL)
  394.     {
  395.       FPRINTF(stderr,"%s: Couldn't open display %s\n", progname, display) ;
  396.       exit(1) ;
  397.     }
  398.   xfd = ConnectionNumber(dpy) ;
  399.   reve_DB = NULL ;
  400.   igc     = NULL ;
  401. }
  402.  
  403.  
  404. int
  405. init_ws_type()
  406. {
  407.   screen = DefaultScreen(dpy) ;
  408.   visual = DefaultVisual(dpy, screen) ;
  409.   root   = RootWindow(dpy, screen) ;
  410.  
  411.   if (!geometry) STRCPY(geometry, XGetDefault(dpy, progname, "Geometry")) ;
  412.  
  413.   foregnd   = BlackPixel(dpy, screen) ;
  414.   backgnd   = WhitePixel(dpy, screen) ;
  415.   scr_depth = DefaultDepth(dpy, screen) ;
  416.  
  417.   cursor[(int) CANVASCUR] = XCreateFontCursor(dpy, XC_top_left_arrow) ;
  418.   cursor[(int) HOURGLASS] = XCreateFontCursor(dpy, XC_watch) ;
  419.   no_pixmap = XCreateBitmapFromData(dpy, root, (char *) nocur_bits, 16, 16) ;
  420.   cursor[(int) NOCURSOR]  = XCreatePixmapCursor(dpy, no_pixmap, no_pixmap,
  421.                                                 &FGcolor, &BGcolor, 0, 0) ;
  422.  
  423.   gtype      = GX11 ;          /* Graphics type. */
  424.   move_delta = 10 ;
  425.  
  426.   if (xdebug == TRUE) XSynchronize(dpy, TRUE) ;
  427.   images[(int) BUT_STENCIL] = load_image(Sbutton_bits) ;
  428.   images[(int) BUT_INVERT]  = load_image(Ibutton_bits) ;
  429.   images[(int) BUT_NORMAL]  = load_image(Nbutton_bits) ;
  430.   images[(int) CY_NORMAL]   = load_image(Ncycle_bits) ;
  431.   images[(int) CY_STENCIL]  = load_image(Scycle_bits) ;
  432.   images[(int) CY_LINVERT]  = load_image(Lcycle_bits) ;
  433.   images[(int) CY_RINVERT]  = load_image(Rcycle_bits) ;
  434.   images[(int) TOGGLE_ON]   = load_image(Sch_on_bits) ;
  435.   images[(int) TOGGLE_OFF]  = load_image(Sch_off_bits) ;
  436.   images[(int) P_WHITE]     = load_image(white_bits) ;
  437.   images[(int) P_BLACK]     = load_image(black_bits) ;
  438.   images[(int) S_MOVE]      = load_image(move_bits) ;
  439.   images[(int) S_SUGGEST]   = load_image(suggest_bits) ;
  440.  
  441.   return(0) ;
  442. }
  443.  
  444.  
  445. static void
  446. load_colors()     /* Create and load reve color map. */
  447. {
  448.   XColor ccol ;
  449.   int i, numcolors ;
  450.  
  451.   iscolor = 0 ;
  452.   if (DisplayCells(dpy, screen) > 2)
  453.     {
  454.       iscolor = 1 ;
  455.       numcolors = 0 ;
  456.       for (i = 0; i < REVE_USEDCOLORSIZE; i++)
  457.         {
  458.           if (colstr[i] == NULL ||
  459.               (XParseColor(dpy, DefaultColormap(dpy, screen),
  460.                            colstr[i], &ccol) == 0))
  461.             {
  462.               ccol.flags = DoRed | DoGreen | DoBlue ;
  463.               ccol.red   = (unsigned short) (rcols[i] << 8) ;
  464.               ccol.green = (unsigned short) (gcols[i] << 8) ;
  465.               ccol.blue  = (unsigned short) (bcols[i] << 8) ;
  466.             }
  467.           if (XAllocColor(dpy,
  468.               DefaultColormap(dpy, screen), &ccol) == True)
  469.             palette[numcolors++] = ccol.pixel ;
  470.         }
  471.       if (numcolors < REVE_USEDCOLORSIZE)
  472.         {
  473.           FPRINTF(stderr, "%s: cannot allocate colors.\n", progname) ;
  474.           exit(1) ;
  475.         }
  476.     }
  477. }
  478.  
  479.  
  480. Pixmap
  481. load_image(cbuf)
  482. unsigned char cbuf[] ;
  483. {
  484.   Pixmap pixmap ;
  485.  
  486.   if (igc == NULL)
  487.     {
  488.       pixmap = XCreatePixmap(dpy, root, 64, 64, 1) ;
  489.       gc_mask = GCForeground | GCBackground | GCGraphicsExposures ;
  490.       gc_val.foreground = foregnd ;
  491.       gc_val.background = backgnd ;
  492.       gc_val.graphics_exposures = False ;
  493.       igc = XCreateGC(dpy, pixmap, gc_mask, &gc_val) ;
  494.     }
  495.   return(XCreatePixmapFromBitmapData(dpy, root, (char *) cbuf,
  496.                                      64, 64, 1, 0, 1)) ;
  497. }
  498.  
  499.  
  500. /*  Get the resource databases. These are looked for in the following ways:
  501.  *
  502.  *  Classname file in the app-defaults directory. In this case, Classname
  503.  *  is Reve.
  504.  *
  505.  *  Classname file in the directory specified by the XUSERFILESEARCHPATH
  506.  *  or XAPPLRESDIR environment variable.
  507.  *
  508.  *  Property set using xrdb, accessible through the XResourceManagerString
  509.  *  macro or, if that is empty, the ~/.Xdefaults file.
  510.  *
  511.  *  XENVIRONMENT environment variable or, if not set, .Xdefaults-hostname
  512.  *  file.
  513.  *
  514.  *  REVEDEFAULTS environment variable or, if not set, the ~/.reverc file.
  515.  */
  516.  
  517. void
  518. load_resources()
  519.   XrmDatabase db ;
  520.   char *home, name[_POSIX_PATH_MAX], *ptr ;
  521.   int len ;
  522.   
  523.   home = getenv("HOME") ;
  524.   XrmInitialize() ;
  525.   STRCPY(name, "/usr/lib/X11/app-defaults/Reve") ;
  526.   
  527. /* Get applications defaults file, if any. */
  528.   
  529.   db = XrmGetFileDatabase(name) ;
  530.   XrmMergeDatabases(db, &reve_DB) ;
  531.  
  532. /* Merge server defaults, created by xrdb. If nor defined, use ~/.Xdefaults. */
  533.  
  534. #ifndef X11R3
  535.   if (XResourceManagerString(dpy) != NULL)
  536.     db = XrmGetStringDatabase(XResourceManagerString(dpy)) ;
  537.   else
  538. #endif /*X11R3*/
  539.     { 
  540.       SPRINTF(name, "%s/.Xdefaults", home) ;
  541.       db = XrmGetFileDatabase(name) ;
  542.     }
  543.   XrmMergeDatabases(db, &reve_DB) ;
  544.  
  545. /*  Open XENVIRONMENT file or, if not defined, the .Xdefaults, and merge
  546.  *  into existing database.
  547.  */
  548.  
  549.   if ((ptr = getenv("XENVIRONMENT")) == NULL)
  550.     {
  551.       SPRINTF(name, "%s/.Xdefaults-", home) ;
  552.       len = strlen(name) ;
  553.       GETHOSTNAME(name+len, _POSIX_PATH_MAX-len) ;
  554.       db = XrmGetFileDatabase(name) ;
  555.     }
  556.   else db = XrmGetFileDatabase(ptr) ;
  557.   XrmMergeDatabases(db, &reve_DB) ;
  558.  
  559. /*  Finally merge in Reve defaults via REVEDEFAULTS or, if not defined, the
  560.  *  ~/.reverc file.
  561.  */
  562.  
  563.   if ((ptr = getenv("REVEDEFAULTS")) == NULL)
  564.     {
  565.       SPRINTF(name, "%s/.reverc", home) ;
  566.       db = XrmGetFileDatabase(name) ;
  567.     }
  568.   else db = XrmGetFileDatabase(ptr) ;
  569.   XrmMergeDatabases(db, &reve_DB) ;
  570. }
  571.  
  572.  
  573. /*ARGSUSED*/
  574. void
  575. lock_screen(state)     /* Turn graphics locking on or off - null routine. */
  576. enum bltype state ;
  577. {}
  578.  
  579.  
  580. void
  581. make_canvas() {}            /* Null routine, see the make_frame routine. */
  582.  
  583.  
  584. void
  585. make_frame(argc, argv)      /* Create reve window/icon. */
  586. int argc ;
  587. char *argv[] ;
  588. {
  589.   unsigned int h, w ;       /* Window dimensions. */
  590.   int flags ;
  591.   int x, y ;                /* Window position. */
  592.  
  593.   opvals[(int) RCLR] = GXclear ;
  594.   opvals[(int) RSRC] = GXcopy ;
  595.   opvals[(int) RINV] = GXxor ;
  596.  
  597.   if (!monochrome) load_colors() ;
  598.   reve_icon = load_image(reve_bits) ;
  599.  
  600.   size.flags  = PPosition | PMinSize | PSize ;
  601.   size.x      = 0 ;
  602.   size.y      = 0 ;
  603.   size.width  = board_width ;
  604.   size.height = board_height ;
  605.   size.min_width = size.min_height = MINBOARDSIZE ;
  606.  
  607.   if (strlen(geometry))
  608.     {
  609.       flags = XParseGeometry(geometry, &x, &y, &w, &h) ;
  610.       if (XValue & flags)
  611.         {
  612.           if (XNegative & flags)
  613.             x = DisplayWidth(dpy, screen) + x - size.width ;
  614.             size.flags |= USPosition ;
  615.             size.x = x ;
  616.         }
  617.       if (YValue & flags)
  618.         {
  619.           if (YNegative & flags)
  620.             y = DisplayHeight(dpy, screen) + y - size.height ;
  621.             size.flags |= USPosition ;
  622.             size.y = y ;
  623.         }
  624.     }
  625.  
  626.   gframe = XCreateSimpleWindow(dpy, root,
  627.                                size.x, size.y, size.width, size.height,
  628.                                REVE_BORDER_WIDTH, foregnd, backgnd) ;
  629.  
  630.   protocol_atom = XInternAtom(dpy, "WM_PROTOCOLS", False) ;
  631.   kill_atom     = XInternAtom(dpy, "WM_DELETE_WINDOW", False) ;
  632.  
  633.   XSetStandardProperties(dpy, gframe, "reve", "Board", reve_icon,
  634.                          argv, argc, &size) ;
  635. #ifndef X11R3
  636.   XSetWMProtocols(dpy, gframe, &kill_atom, 1) ;
  637. #endif /*X11R3*/
  638.  
  639.   wm_hints.icon_x = ix ;
  640.   wm_hints.icon_y = iy ;
  641.   wm_hints.input = True ;
  642.   wm_hints.icon_pixmap = reve_icon ;
  643.   wm_hints.flags = InputHint | IconPixmapHint ;
  644.   if (iconic)
  645.     {    
  646.       wm_hints.initial_state = IconicState ;
  647.       wm_hints.flags |= StateHint ;
  648.     }    
  649.   XSetWMHints(dpy, gframe, &wm_hints) ;
  650.          
  651. /* Set XA_WM_CLASS so things that depend on NAME work. */
  652.  
  653.   XSetClassHint(dpy, gframe, &class_hint) ;
  654.  
  655. /* Create control panel. */
  656.  
  657.   cframe = make_subwindow(0, board_height + BORDER_SIZE + LABEL_SIZE,
  658.                           PANEL_WIDTH, PANEL_HEIGHT,
  659.                           "reve", "Control", argc, argv) ;
  660.   XSetWMHints(dpy, cframe, &wm_hints) ;
  661.  
  662. /*  Create property window. */
  663.  
  664.   pframe = make_subwindow(board_width + (2 * BORDER_SIZE), 0,
  665.                           PROPS_WIDTH, PROPS_HEIGHT,
  666.                           "reve properties", "Props", argc, argv) ;
  667.  
  668. /* Create graphics contexts. */
  669.  
  670.   gc_mask = GCForeground | GCBackground | GCGraphicsExposures ;
  671.   gc_val.foreground = foregnd ;
  672.   gc_val.background = backgnd ;
  673.   gc_val.graphics_exposures = False ;
  674.   gc = XCreateGC(dpy, root, gc_mask, &gc_val) ;
  675.  
  676.   ropgc = XCreateGC(dpy, root, gc_mask, &gc_val) ;
  677.   XSetFillStyle(dpy, ropgc, FillStippled) ;
  678.  
  679.   stencilgc = XCreateGC(dpy, root, gc_mask, &gc_val) ;
  680.   XSetFillStyle(dpy, stencilgc, FillOpaqueStippled) ;
  681.  
  682.   pid = fork_child() ;
  683. }
  684.  
  685.  
  686. void
  687. make_help_window(argc, argv)
  688. int argc ;
  689. char *argv[] ;
  690. {
  691.   int fontwidth ;
  692.  
  693.   fontwidth   = font[(int) HFONT]->max_bounds.rbearing +
  694.                 font[(int) HFONT]->min_bounds.lbearing ;
  695.   help_height = ((font_heights[(int) HFONT] + 1) * HELP_ROWS) +
  696.                  (4 * CGAP) + CHEIGHT ;
  697.   help_width  = (fontwidth * HELP_COLS) + (2 * CGAP) ;
  698.  
  699.   hframe = make_subwindow(board_width + (2 * BORDER_SIZE), 0,
  700.                           help_width, help_height,
  701.                           "reve help", "Help", argc, argv) ;
  702. }
  703.  
  704.  
  705. void
  706. make_icon() {}        /* Null routine - icon created in make_frame. */
  707.  
  708.  
  709. void
  710. make_pieces(width, height)
  711. int width, height ;
  712. {
  713.   bborder = BBORDER ;
  714.  
  715.   cell_width   = (width  - (2 * bborder)) / BOARD_SIZE ;
  716.   cell_height  = (height - (2 * bborder)) / BOARD_SIZE ;
  717.  
  718.   pieceXmargin = cell_width  / 8 ;
  719.   pieceYmargin = cell_height / 8 ;
  720.  
  721.   pieceXrad = (cell_width  - (2 * pieceXmargin)) / 2 ;
  722.   if (pieceXrad > MAXPRAD)
  723.     {
  724.       pieceXrad    = MAXPRAD ;
  725.       pieceXmargin = (cell_width - (2 * pieceXrad)) / 2 ;
  726.     }
  727.  
  728.   pieceYrad = (cell_height - (2 * pieceYmargin)) / 2 ;
  729.   if (pieceYrad > MAXPRAD)
  730.     {
  731.       pieceYrad    = MAXPRAD ;
  732.       pieceYmargin = (cell_height - (2 * pieceYrad)) / 2 ;
  733.     }
  734.  
  735.   XSetFunction(dpy, igc, GXclear) ;
  736.   XCopyArea(dpy, images[(int) P_WHITE], images[(int) P_WHITE], igc,
  737.             0, 0, 2 * MAXPRAD, 2 * MAXPRAD, 0, 0) ;
  738.   XCopyArea(dpy, images[(int) P_BLACK], images[(int) P_BLACK], igc, 
  739.             0, 0, 2 * MAXPRAD, 2 * MAXPRAD, 0, 0) ;
  740.  
  741.   XSetFunction(dpy, igc, GXset) ;
  742.   XDrawArc(dpy, images[(int) P_WHITE], igc,
  743.            0, 0, 2 * pieceXrad - 1, 2 * pieceYrad - 1, 0, 360 * 64) ;
  744.   XFillArc(dpy, images[(int) P_BLACK], igc,
  745.            0, 0, 2 * pieceXrad - 1, 2 * pieceYrad - 1, 0, 360 * 64) ;
  746. }
  747.  
  748.  
  749. Window
  750. make_subwindow(x, y, width, height, wname, iname, argc, argv)
  751. int argc, x, y, width, height ;
  752. char *wname, *iname, *argv[] ;
  753. {
  754.   Window w ;
  755.  
  756.   size.flags = PMinSize | PMaxSize | PPosition | PSize ;
  757.   size.x = x ;
  758.   size.y = y ;
  759.   size.max_width  = size.min_width  = size.width  = width ;
  760.   size.max_height = size.min_height = size.height = height ;
  761.  
  762.   w = XCreateSimpleWindow(dpy, root, size.x, size.y,
  763.                           size.max_width, size.max_height,
  764.                           REVE_BORDER_WIDTH, foregnd, backgnd) ;
  765.  
  766.   XSetStandardProperties(dpy, w, wname, iname, reve_icon, argv, argc, &size) ;
  767. #ifndef X11R3
  768.   XSetWMProtocols(dpy, w, &kill_atom, 1) ;
  769. #endif /*X11R3*/
  770.   XSetTransientForHint(dpy, w, gframe) ;
  771.   return(w) ;
  772. }
  773.  
  774.  
  775. void
  776. open_reve()
  777. {
  778.   XMapWindow(dpy, gframe) ;
  779. }
  780.  
  781.  
  782. void
  783. process_event()         /* Determine event type. */
  784. {
  785.   XClientMessageEvent *ev ;
  786.   XConfigureEvent *con ;
  787.   XKeyPressedEvent *key_event ;
  788.   KeySym keysym ;
  789.   char chs[2] ;
  790.  
  791.   nextc = IGNORE_EVENT ;
  792.        if (event.xany.window == gframe) curwin = W_BOARD ;
  793.   else if (event.xany.window == cframe) curwin = W_PANEL ;
  794.   else if (event.xany.window == pframe) curwin = W_PROPS ;
  795.   else if (event.xany.window == hframe) curwin = W_HELP ;
  796.  
  797.   switch (event.type)
  798.     {
  799.       case ClientMessage    : /* Catch ICCCM kill from WM. */
  800.  
  801.                               ev = (XClientMessageEvent *) &event ;
  802.                               if (ev->message_type == protocol_atom &&
  803.                                   ev->data.l[0] == kill_atom)
  804.                                 {
  805.                                   if (curwin == W_BOARD) destroy_reve() ;
  806.                                   else if (curwin == W_HELP)
  807.                                     {
  808.                                       help_showing = FALSE ;
  809.                                       XUnmapWindow(dpy, event.xany.window) ;
  810.                                     }
  811.                                   else if (curwin == W_PROPS)
  812.                                     {
  813.                                       props_showing = FALSE ;
  814.                                       XUnmapWindow(dpy, event.xany.window) ;
  815.                                     }
  816.                                 }
  817.                               nextc = IGNORE_EVENT ;
  818.                               break ;
  819.  
  820.       case ConfigureNotify  : con = (XConfigureEvent *) & event ;
  821.                               if (curwin == W_BOARD &&
  822.                                   (board_width != con->width ||
  823.                                    board_height != con->height))
  824.                                 {
  825.                                   board_width = con->width ;
  826.                                   board_height = con->height ;
  827.                                   make_pieces(board_width, board_height) ;
  828.                                   paint_board() ;
  829.                                 }
  830.                               break ;
  831.  
  832.       case Expose           : nextc = process_expose((XExposeEvent *) &event) ;
  833.                               break ;
  834.  
  835.       case KeyPress         : key_event = (XKeyPressedEvent *) &event ;
  836.                               curx = key_event->x ;
  837.                               cury = key_event->y ;
  838.                               (void) XLookupString(key_event, chs, 1,
  839.                                                    &keysym,
  840.                                                    (XComposeStatus *) NULL) ;
  841.                               if (keysym == XK_Shift_L ||
  842.                                   keysym == XK_Shift_R) nextc = IGNORE_EVENT ;
  843.                               else
  844.                                 {
  845.                                   cur_ch = chs[0] ;
  846.                                   nextc = KEYBOARD ;
  847.                                 }
  848.                               break ;
  849.  
  850.       case EnterNotify      : nextc = ENTER_WINDOW ;
  851.                               break ;
  852.  
  853.       case LeaveNotify      : nextc = EXIT_WINDOW ;
  854.                               break ;
  855.  
  856.       case MotionNotify     : if (processing == FALSE)
  857.                                 {
  858.                                   nextc = MOUSE_MOVING ;
  859.                                   curx = event.xbutton.x ;
  860.                                   cury = event.xbutton.y ;
  861.                                 }
  862.                               break ;
  863.  
  864.       case ButtonPress      : curx = event.xbutton.x ;
  865.                               cury = event.xbutton.y ;
  866.                               if (event.xbutton.button == Button1)
  867.                                 nextc = LEFT_DOWN ;
  868.                               else if (event.xbutton.button == Button2)
  869.                                 nextc = MIDDLE_DOWN ;
  870.                               else if (event.xbutton.button == Button3)
  871.                                 nextc = RIGHT_DOWN ;
  872.                               break ;
  873.  
  874.       case ButtonRelease    : curx = event.xbutton.x ;
  875.                               cury = event.xbutton.y ;
  876.                               if (event.xbutton.button == Button1)
  877.                                 nextc = LEFT_UP ;
  878.                               else if (event.xbutton.button == Button2)
  879.                                 nextc = MIDDLE_UP ;
  880.                               else if (event.xbutton.button == Button3)
  881.                                 nextc = RIGHT_UP ;
  882.     }
  883. }
  884.  
  885.  
  886. static int
  887. process_expose(event)
  888. XExposeEvent *event ;
  889. {
  890.   int docframe, dogframe, dohframe, dopframe ;
  891.  
  892.   docframe = dogframe = dohframe = dopframe = 0 ;
  893.   do
  894.     {
  895.       if (event->count == 0 && event->window == gframe) dogframe++ ;
  896.       if (event->count == 0 && event->window == cframe) docframe++ ;
  897.       if (event->count == 0 && event->window == pframe) dopframe++ ;
  898.       if (event->count == 0 && event->window == hframe) dohframe++ ;
  899.     }
  900.   while (XCheckMaskEvent(dpy, ExposureMask, (XEvent *) event)) ;
  901.  
  902. /* Events handled here, in case of multiple simultaneous occurances. */
  903.  
  904.   if (dogframe) paint_board() ;
  905.   if (docframe) paint_panel() ;
  906.   if (dohframe) paint_help() ;
  907.   if (dopframe) paint_prop_sheet() ;
  908.   return(IGNORE_EVENT) ;
  909. }
  910.  
  911.  
  912. void
  913. raise_reve()
  914. {
  915.   XRaiseWindow(dpy, gframe) ;
  916. }
  917.  
  918.  
  919. void
  920. set_cursor(ctype)
  921. enum curtype ctype ;
  922. {
  923.   XDefineCursor(dpy, gframe, cursor[(int) ctype]) ;
  924.   XDefineCursor(dpy, cframe, cursor[(int) ctype]) ;
  925.   XDefineCursor(dpy, hframe, cursor[(int) ctype]) ;
  926.   XDefineCursor(dpy, pframe, cursor[(int) ctype]) ;
  927.   XFlush(dpy) ;
  928. }
  929.  
  930.  
  931. void
  932. set_frame(wtype, showing)
  933. enum win_type wtype ;
  934. int showing ;
  935. {
  936.   Window window ;
  937.  
  938.        if (wtype == W_HELP)  window = hframe ;
  939.   else if (wtype == W_PROPS) window = pframe ;
  940.  
  941.   if (showing) XMapWindow(dpy, window) ;
  942.   else         XUnmapWindow(dpy, window) ;
  943. }
  944.  
  945.  
  946. void
  947. show_windows()
  948. {
  949.   XSelectInput(dpy, gframe, FRAME_MASK) ;
  950.   XSelectInput(dpy, cframe, FRAME_MASK) ;
  951.   XSelectInput(dpy, hframe, FRAME_MASK) ;
  952.   XSelectInput(dpy, pframe, FRAME_MASK) ;
  953.  
  954.   XMapWindow(dpy, gframe) ;
  955.   XMapWindow(dpy, cframe) ;
  956.   if (help_showing)  XMapWindow(dpy, hframe) ;
  957.   if (props_showing) XMapWindow(dpy, pframe) ;
  958. }
  959.  
  960.  
  961. void
  962. start_tool(dtype)            /* Start event dispatcher and display. */
  963. enum disp_type dtype ;
  964. {
  965.   int fd ;                       /* Type of this input. */
  966.   struct timeval tval ;          /* Set to go off, once a second. */
  967.  
  968.   show_windows() ;
  969.   tval.tv_usec = 0 ;
  970.   tval.tv_sec  = 1 ;
  971.   for (;;)
  972.     {
  973.       XFlush(dpy) ;
  974. #ifdef NOSELECT
  975. #ifdef HASPOLL
  976.       fd = -1 ;
  977.       POLL(pfd, npfd, -1) ;
  978.            if (pfd[0].revents == POLLIN) fd = DPY_INPUT ;
  979.       else if (pfd[1].revents == POLLIN) fd = COMP_INPUT ;
  980.       else if (pfd[2].revents == POLLIN) fd = SOCK_INPUT ;
  981. #else
  982.       fd = 0 ;
  983. #endif /*HASPOLL*/
  984. #else
  985.       fd = -1 ;
  986.       readmask = fullmask ;
  987. #ifdef NO_43SELECT
  988.       SELECT(32, &readmask, 0, 0, &tval) ;
  989.            if (readmask && (1 << xfd))           fd = DPY_INPUT ;
  990.       else if (readmask && (1 << pipe_io[1][0])) fd = COMP_INPUT ;
  991.       else if (readmask && (1 << socketfd))      fd = SOCK_INPUT ;
  992. #else
  993.       SELECT(FD_SETSIZE, &readmask, (fd_set *) 0, (fd_set *) 0, &tval) ;
  994.            if (FD_ISSET(xfd,           &readmask)) fd = DPY_INPUT ;
  995.       else if (FD_ISSET(pipe_io[1][0], &readmask)) fd = COMP_INPUT ;
  996.       else if (FD_ISSET(socketfd,      &readmask)) fd = SOCK_INPUT ;
  997. #endif /*NO_43SELECT*/
  998. #endif /*NOSELECT*/
  999.  
  1000.       switch (fd)
  1001.         {
  1002.           case DPY_INPUT  : while (XPending(dpy))
  1003.                               {
  1004.                                 get_event() ;
  1005.                                 handle_event() ;
  1006.                               }
  1007.                             break ;
  1008. #ifdef REMOTE_PLAYER
  1009.           case SOCK_INPUT : read_from_sock(socketfd) ;    /* Remote human. */
  1010.                             break ;
  1011. #endif /* REMOTE_PLAYER */
  1012.           case COMP_INPUT : read_from_reve(pipe_io[1][0]) ;   /* Computer. */
  1013.         }
  1014.       if (cmode != GAME_OVER) update_clock(next_player, FALSE) ;
  1015.     }
  1016. }
  1017.